package com.eis.function.in;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eis.admin.mvc.bean.xml.ConnectorConfigureBean;
import com.eis.admin.mvc.bean.xml.ConnectorConfigureParaBean;
import com.eis.admin.mvc.bean.xml.FunctionParameter;
import com.eis.admin.mvc.bean.xml.FunctionParameterElement;
import com.eis.function.in.base.BaseTask;
import com.eis.persist.dao.FunctionDAO;
import com.eis.persist.dao.impl.FunctionDAOImpl;
import com.eis.persist.model.function.PersistFunction;
import com.eis.persist.model.function.PersistFunctionParameter;
import com.eis.thirdsys.connector.ConnectorStatics;
import com.eis.thirdsys.connector.ThirdSysConnector;
import com.eis.thirdsys.connector.ThirdSysConnectorFactory;
import com.eis.thirdsys.connector.conf.ConnectorConfig;
import com.eis.thirdsys.connector.parameter.ParameterElementValue;
import com.eis.thirdsys.connector.parameter.ParameterValue;
import com.eis.util.XmlUtil;

/**
 *
 * 
 * @author panwei01
 *
 */
public class FunctionDataFetcher extends BaseTask {
	private static final Logger logger = LoggerFactory.getLogger(FunctionDataFetcher.class);
	
	private XmlUtil xmlUtil;

	@SuppressWarnings("deprecation")
	@Override
	public void runTask() {
		// load all functions
		FunctionDAO functionDAO = new FunctionDAOImpl(dataSource);
		Map<Integer, PersistFunction> sapFunctions = functionDAO.loadALlEnabledFunctions();
		Date now = new Date();

		// load latest schema by connector, and update original schema
		for (PersistFunction oneFunction : sapFunctions.values()) {
			try {
				
				ConnectorConfig connectorConfig = null;
				if (oneFunction.getBizSystem().getConnectorStaticsClassName() != null 
						&& oneFunction.getBizSystem().getConnectorStaticsClassName().trim().length() > 0) {
					ThirdSysConnectorFactory thirdSysConnectorFactory = new ThirdSysConnectorFactory(oneFunction.getBizSystem().getConnectorStaticsClassName());
					List<ParameterValue> callParameters = convertParameterDataType(oneFunction.getFunctionParameter(), thirdSysConnectorFactory.getConnectorStatics());
					connectorConfig = thirdSysConnectorFactory.newConnectorConfig();

					if (oneFunction.getConnectorConfig() != null) {
						ConnectorConfigureBean parsed = (ConnectorConfigureBean) xmlUtil.parseXml(oneFunction.getConnectorConfig().getConfigXml());
						for (ConnectorConfigureParaBean oneConfig : parsed.getConnectorConfigureParaBean()) {
							connectorConfig.setOneConf(oneConfig.getKey(), oneConfig.getValue());
						}
					}
				

					ThirdSysConnector connector = thirdSysConnectorFactory.newInstance(connectorConfig);
	
					ArrayList<HashMap<String, Object>> latestSchema = connector.getFunctionSchema(oneFunction.getFunctionID(), oneFunction.getDatafetchID(), callParameters);
	
					functionDAO.updateOrInsertFunctionSchema(oneFunction, latestSchema, now);
				}
			} catch (Throwable t) {
				logger.error("Error when create/update schema: " + oneFunction.getFunctionID(), t);
			}
		}

		sapFunctions = functionDAO.loadALlEnabledFunctions(); // load again if schema get updated
		// load function data
		for (PersistFunction oneFunction : sapFunctions.values()) {
			try {
				Date lastFechDataTime = oneFunction.getLastDataFetchTime();
				// minus 1 hour
				Calendar c = Calendar.getInstance();
				c.setTime(lastFechDataTime);
				c.add(Calendar.HOUR, -1);
				lastFechDataTime = c.getTime();
				
				logger.info("start fetch function(" + oneFunction.getFunctionID() + ") data at(GMT time): " + now.toGMTString()+ " last fetch(GMT time) minus 1 hour: " + lastFechDataTime.toGMTString());
				
				ConnectorConfig connectorConfig = null;
				
				if (oneFunction.getBizSystem().getConnectorStaticsClassName() != null 
						&& oneFunction.getBizSystem().getConnectorStaticsClassName().trim().length() > 0) {
					ThirdSysConnectorFactory thirdSysConnectorFactory = new ThirdSysConnectorFactory(oneFunction.getBizSystem().getConnectorStaticsClassName());
					connectorConfig = thirdSysConnectorFactory.newConnectorConfig();
					List<ParameterValue> callParameters = convertParameterDataType(oneFunction.getFunctionParameter(), thirdSysConnectorFactory.getConnectorStatics());
					
					if (oneFunction.getConnectorConfig() != null) {
						ConnectorConfigureBean parsed = (ConnectorConfigureBean) xmlUtil.parseXml(oneFunction.getConnectorConfig().getConfigXml());
						for (ConnectorConfigureParaBean oneConfig : parsed.getConnectorConfigureParaBean()) {
							connectorConfig.setOneConf(oneConfig.getKey(), oneConfig.getValue());
						}
					}
				

					ThirdSysConnector connector = thirdSysConnectorFactory.newInstance(connectorConfig);
	
					ArrayList<HashMap<String, Object>> functionData = connector.getFunctionData(oneFunction.getFunctionID(), oneFunction.getDatafetchID(), lastFechDataTime, callParameters);
					
	
					int count = functionDAO.batchSaveFunctionData(oneFunction, functionData, now);
					if (count > 0) {
						// update lastFetchDataTime
						functionDAO.updateFunctionDateFetchTime(now, oneFunction.getFunctionID());
					}
					
					logger.info("end fetch function(" + oneFunction.getFunctionID() + ") data at(GMT time): " + new Date().toGMTString()+ " last fetch(GMT time) minus 1 hour: " + lastFechDataTime.toGMTString());
				}
			} catch (Throwable t) {
				logger.error("Error when insert/update function data: " + oneFunction.getFunctionID() + " \r\n" + t.toString(), t);
			}
		}
	}
	
	
	public void setXmlUtil(XmlUtil xmlUtil) {
		this.xmlUtil = xmlUtil;
	}

	private List<ParameterValue> convertParameterDataType(List<PersistFunctionParameter> persistFunctionParameter, ConnectorStatics statics) {
		List<ParameterValue> returned = new ArrayList<ParameterValue>();
		
		for(PersistFunctionParameter onePara : persistFunctionParameter) {
			ParameterValue converted = new ParameterValue(statics);
			returned.add(converted);
			
			FunctionParameter fp = (FunctionParameter) xmlUtil.parseXml(onePara.getParameterXMl());
			for (FunctionParameterElement element : fp.getElements()) {
				ParameterElementValue value = new ParameterElementValue();
				value.setName(element.getElementName());
				value.setValue(element.getElementValue());
				converted.addElementValue(value);
			}
		}
		return returned;
	}
}
